<?php

declare(strict_types=1);

namespace app\logic\api\admin;

use zhtp\Random;
use app\logic\api\ApiBaseLogic;
use app\model\api\admin\Admin;
use app\library\api\admin\Auth;
use app\common\constant\CacheKey;

class LoginLogic extends ApiBaseLogic
{
    protected $auth;
    public function __construct()
    {
        $this->auth = Auth::instance();
    }

    public function login($data)
    {
        $lgc_re = $this->loginInner($data);

        if ($lgc_re['code'] == 200) {
            cache('_need_login_captcha_' . $data['username'], '0', 600);
        } else {
            cache('_need_login_captcha_' . $data['username'], '1', 600);
        }

        return $lgc_re;
    }
    private function loginInner($data)
    {
        // 边验证参数+边更新数据
        $user = Admin::where(['username' => $data['username']])->find();
        if (!$user) {
            return $this->fail('用户名或密码不正确');
        }
        if (config('zhtp.login_failure_retry') && $user->login_fail_num >= 60 && time() - $user->login_fail_time < 86400) {
            return $this->fail(date('Ymd H:i', $user->login_fail_time) . ',请24小时后再尝试');
        }

        if ($user->password != password_md5($data['password'], $user->salt)) {
            $user->login_fail_time = time();
            $user->login_fail_num++;
            $user->save();
            return $this->fail('用户名或密码不正确');
        }
        if ($user['status'] == Admin::STATUS_DISABLE) {
            return $this->fail('账户已禁用');
        }

        // 登录成功
        $user->login_nums += 1;
        $user->login_fail_num = 0;
        $user->login_time = time();
        $user->login_ip = request()->ip();
        $user->token = Random::uuid();
        $user->save();

        // 生成access_token+refresh_token
        $jwt_data = [
            'id' => $user['id'],
            'username' => $user['username'],
            'token' => $user['token'],
            'login_ip' => $user['login_ip'],
            'from' => '1', // 1admin 2member 3mpfriend
        ];
        $access_token = $this->auth->encodeJWT($jwt_data, random_int(900, 3600)); // 15分钟到60分钟有效

        $refresh_token = $this->auth->encodeJWT($jwt_data, $data['keep_time'] ?? 86400);
        cache(CacheKey::RefreshTokenAdmin . md5($refresh_token['token']), '1', $refresh_token['keep_time']);

        // 返回
        $user_info = [
            'avatar' => $user['avatar'],
            'username' => $user['username'],
            'nickname' => $user['username'],
            'roles' => [],// $this->getRolesCode($user['id']),
            'permissions' => is_super_admin() ? ['*:*:*'] : [],
            'accessToken' => $access_token['token'],
            'refreshToken' => $refresh_token['token'],
            'expires' => date('Y-m-d H:i:s', $access_token['exp']),
        ];

        return $this->ok('登录成功', $user_info);
    }

    public function refreshToken($data)
    {
        // 也可在此重新解码
        $old_jwt_data = $data['old_jwt_data'];
        request()->x_token_user = $old_jwt_data['data']; // 刷新令牌的用户信息-临时给request-log用

        // 生成新access_token
        $new_jwt_data = $old_jwt_data['data'];
        $access_token = $this->auth->encodeJWT($new_jwt_data, random_int(900, 3600)); // 15分钟到60分钟有效

        $new_refresh_keep_time = (int) $old_jwt_data['exp'] - time(); //用原过期时间
        if ($new_refresh_keep_time < 0) {
            return $this->fail('刷新令牌已过期');
        }

        $refresh_token = $this->auth->encodeJWT($new_jwt_data, $new_refresh_keep_time); // 重新生成refreshToken
        cache(CacheKey::RefreshTokenAdmin . md5($data['refresh_token']), null); // 旧刷新令牌作废
        cache(CacheKey::RefreshTokenAdmin . md5($refresh_token['token']), '1', $refresh_token['keep_time']);

        $re_info = [
            'accessToken' => $access_token['token'],
            'refreshToken' => $refresh_token['token'],
            'expires' => date('Y-m-d H:i:s', $access_token['exp']),
        ];

        return $this->ok('刷新成功', $re_info);
    }

    public function getRoutes($data)
    {
        $auth_routes = $this->auth->getAuthMenus($data['user_id']);
        return $this->ok('ok', $auth_routes);
    }


    private function getRolesCode(int $user_id)
    {
        $roles = $this->auth->getGroups($user_id);
        return array_column($roles, 'code');
    }

}
